package values

import (
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"gitee.com/gousing/values/internal"
)

// ToBool 转换目标为Bool, 如果转换失败, 则返回false
func ToBool(v any) bool {
	if to, err := ToBoolE(v); err == nil {
		return to
	}
	return false
}

// ToBoolD 转换目标为Bool, 如果转换失败, 则返回指定的默认值
func ToBoolD(v any, defaultVal bool) bool {
	if to, err := ToBoolE(v); err == nil {
		return to
	}
	return defaultVal
}

// ToBoolE 转换目标为Bool, 如果转换失败, 则返回false和错误信息
func ToBoolE(v any) (bool, error) {
	v = UnderefVal(v)
	if v == nil {
		return false, errors.New("ToBoolE: unable to nil to bool")
	}
	switch b := v.(type) {
	case bool:
		return b, nil
	case string:
		return StringToBoolE(b)
	case int:
		return b != 0, nil
	case int8:
		return b != 0, nil
	case int16:
		return b != 0, nil
	case int32:
		return b != 0, nil
	case int64:
		return b != 0, nil
	case uint:
		return b != 0, nil
	case uint8:
		return b != 0, nil
	case uint16:
		return b != 0, nil
	case uint32:
		return b != 0, nil
	case uint64:
		return b != 0, nil
	case float32:
		return b != 0, nil
	case float64:
		return b != 0, nil
	case time.Time:
		return !b.IsZero(), nil
	case time.Duration:
		return b != time.Duration(0), nil
	case time.Month:
		return b > 0 && b < 13, nil
	case time.Weekday:
		return b >= 0 && b < 7, nil
	case complex64:
		return b != internal.Zero[complex64](), nil
	case complex128:
		return b != internal.Zero[complex128](), nil
	case json.Number:
		if b.String() == "" {
			return false, nil
		}
		if f, err := b.Float64(); err == nil {
			return f != float64(0), nil
		}
		return false, fmt.Errorf("ToBoolE: unable to (%#v) of type json.Number to bool", v)
	case providerBool:
		return b.Bool(), nil
	default:
		return false, fmt.Errorf("ToBoolE: unable to (%#v) of type %T to bool", v, v)
	}
}
